﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using LabChecker.Models;
using System.Text;
using System.Xml.Linq;
using System.IO;
using LabChecker.Models.Programs;
using LabChecker.ViewModels;
using LabChecker.Properties;

namespace LabChecker.Controllers
{
    public class CheckerController : Controller
    {
        private LabCheckerContext db = new LabCheckerContext();

        public ActionResult Index(bool? fromClient)
        {
            ViewBag.HideMenu = fromClient;
            ViewBag.Subjects = (from subject in db.Subjects.ToList()
                                select new SelectListItem { Text = subject.Name, Value = subject.Id.ToString() });
            return View();
        }

        public JsonResult GetTasksForSubject(int id)
        {
            return Json(
                (from task in db.Tasks where task.Subject.Id == id
                select new { id = task.Id, name = task.Description.Title })
                .ToList()
                .OrderBy(t => int.Parse(t.name.Split(' ')[1])),
                JsonRequestBehavior.AllowGet
            );
        }

        public JsonResult GetTaskDescription(int id)
        {
            return Json(GetFullTaskDescription(db.Tasks.Find(id)), JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        public ActionResult Check(int task_id)
        {
            if (Settings.Default.UseCheckerClient)
            {
                throw new InvalidOperationException("You must use CheckerClient application!");
            }

            var file = Request.Files[0];                        
            var program = new CSharpProgram(new StreamReader(file.InputStream).ReadToEnd());
            var task = db.Tasks.Find(task_id);
            var checkResult = task.Check(program);
            ViewBag.CheckResultViewModel = new CheckResultViewModel(checkResult);
            return View("CheckResult");
        }

        private string GetFullTaskDescription(Task task)
        {
            var fullDescriptionSB = new StringBuilder();
            fullDescriptionSB.Append(@"<table class='layout'>");
            fullDescriptionSB.Append(@"<tr>");
            fullDescriptionSB.Append(@"<td style='vertical-align: top;' class='layout'>");            
            fullDescriptionSB.Append(task.Description.Problem);            
            fullDescriptionSB.Append(@"</td>");
            fullDescriptionSB.Append(@"<td style='padding-left: 20px;' class='layout'>"); 
            fullDescriptionSB.Append(@"<h3>Input</h3>");
            fullDescriptionSB.Append(task.Description.Input);
            fullDescriptionSB.Append(@"<h3>Output</h3>");
            fullDescriptionSB.Append(task.Description.Output);
            fullDescriptionSB.Append(@"<h3>Примеры</h3>");
            var tableElement =
                    new XElement("table",
                    new XAttribute("class", "examplesTable"),
                        new XElement("tr",
                            new XElement("th", "Input"),
                            new XElement("th", "Output")
                        ),
                        task.TestCases.Where(tc => tc.IsExample).Select(tc =>
                            new XElement("tr",
                                new XElement("td", tc.Input.Split('\n').Select(l => new object[2] { new XText(l), new XElement("br") }),
                                    new XAttribute("style", "vertical-align: top")
                                ),
                                new XElement("td", tc.Answer.Split('\n').Select(l => new object[2] { new XText(l), new XElement("br") }),
                                    new XAttribute("style", "vertical-align: top")
                                )
                            )
                        )
                    );
            fullDescriptionSB.Append(tableElement.ToString());
            fullDescriptionSB.Append(@"</td>");
            fullDescriptionSB.Append(@"</tr>");
            fullDescriptionSB.Append(@"</table>"); 
            return fullDescriptionSB.ToString();
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}
